/**
 * @file elevation.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include "lv_watch.h"
#if USE_LV_WATCH_ELEVATION!= 0
#include <stdio.h>
/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/
/**********************
 *  STATIC PROTOTYPES
 **********************/
/**********************
 *  STATIC VARIABLES
 **********************/
static uint32_t elevation_data[ELEVATION_W];
static elevation_mng_t elevation_mng = {};
static const lv_point_t elevation_valid_pos[] = {{0, 0}, {0, 1}};
static void elevation_pressure_prepare_destory(lv_obj_t * activity_obj);
/**********************
 *      MACROS
 **********************/

/**********************
 *   STATIC FUNCTIONS
 **********************/

static void elevation_test_init(void)
{
    uint32_t i, j;
    int8_t z;

    j = 800;

#if LV_WATCH_SIMULATOR_360 == 1
    for(i = 0; i < ELEVATION_W - 230; i++) {
#else
    for(i = 0; i < ELEVATION_W - 120; i++) {
#endif
        if(j == 800) z = 10;
        if(j == 9600) z = -5;

        j+=z;
        elevation_data[i] = j;
    }
#if LV_WATCH_SIMULATOR_360 == 1
    for(; i < ELEVATION_W - 200; i++) {
#else
    for(; i < ELEVATION_W - 100; i++) {
#endif
        elevation_data[i] = 9600 - 10 * i;
    }

    j = 800;
    for(; i < ELEVATION_W; i++) {
        if(j == 800) z = 10;
        if(j == 9600) z = -5;

        j+=z;
        elevation_data[i] = j;
    }

}

static uint32_t elevation_get_data(uint32_t x)
{
    return (ELEVATION_HOR * elevation_data[x]) / ELEVATION_GOAL_STEP;
}

static void elevation_add_record(lv_obj_t * canvas, uint32_t x, lv_color_t start, lv_color_t end)
{
    uint32_t i, h, h_before, offset = 1;
    uint32_t mix;
    lv_color_t act_color;
    uint32_t posx = x;
    if(lv_obj_get_base_dir(canvas) == LV_BIDI_DIR_RTL)
        posx = ELEVATION_W - x - 1;

    h = elevation_get_data(x);
    lv_elevation_obj_ext_t * ext = elevation_pressure_get_ext();

    if(elevation_data[x] >= elevation_data[elevation_mng.highest_x]) {
        elevation_mng.highest_x = x;

        lv_obj_align(ext->elevation_ext.highest_dot, canvas, LV_ALIGN_IN_TOP_LEFT, posx - lv_obj_get_width(ext->elevation_ext.highest_dot) / 2,
                     ELEVATION_HOR - h - lv_obj_get_width(ext->elevation_ext.highest_dot) / 2);
    }

    if((elevation_data[x] <= elevation_data[elevation_mng.lowest_x]) && (elevation_data[x] != 0)) {
        elevation_mng.lowest_x = x;
        lv_obj_align(ext->elevation_ext.lowest_dot, canvas, LV_ALIGN_IN_TOP_LEFT, posx - lv_obj_get_width(ext->elevation_ext.lowest_dot) / 2,
                     ELEVATION_HOR - h - lv_obj_get_width(ext->elevation_ext.lowest_dot) / 2);
    }

    if(x != 0) {
        h_before = elevation_get_data(x - 1);
        if(h_before == h)
            offset = 1;
        else if(h_before < h)
            offset = h - h_before;
        else
            offset = h_before -h;
    } else {
        h_before = h;
    }

    if(h_before <= h) {
        for(i = ELEVATION_HOR - 1; i > ELEVATION_HOR - h + offset; i--) {
            mix = ((h - (ELEVATION_HOR - i)) * 255) / h;
            act_color = lv_color_mix(start, end, mix);
            lv_canvas_set_px(canvas, posx, i, act_color);
        }

        for(; i > ELEVATION_HOR - h; i--) {
            lv_canvas_set_px(canvas, posx, i, LV_COLOR_BLUE);
        }
    } else {
        for(i = ELEVATION_HOR - 1; i > ELEVATION_HOR - h; i--) {
            mix = ((h - (ELEVATION_HOR - i)) * 255) / h;
            act_color = lv_color_mix(start, end, mix);
            lv_canvas_set_px(canvas, posx, i, act_color);
        }

        for(; i > ELEVATION_HOR - h - offset; i--) {
            lv_canvas_set_px(canvas, posx, i, LV_COLOR_BLUE);
        }
    }
}

static lv_obj_t * elevation_add_dot(lv_obj_t * par, lv_obj_t * align_obj, uint16_t x, char * text)
{
    lv_obj_t * dot = lv_obj_create(par, NULL);
    uint32_t posx = x;
    lv_obj_set_size(dot, 1, 2);
    if(lv_obj_get_base_dir(par) == LV_BIDI_DIR_RTL)
        posx = ELEVATION_W - x - 1;
    lv_obj_align(dot, align_obj, LV_ALIGN_OUT_TOP_LEFT, posx, 0);

    if(text) {
        lv_obj_t * label = lv_label_create(par, NULL);
        lv_label_set_text(label, text);
        lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_THEME_WATCH_NIGHT_FONT_12);
        lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
        lv_obj_align(label, dot, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
        lv_obj_set_base_dir(label, LV_BIDI_DIR_LTR);
    }

    return dot;
}

static void elevation_update_display(lv_obj_t * obj, uint32_t x)
{
    char str[20] = {};
    lv_elevation_obj_ext_t * ext = elevation_pressure_get_ext();
    lv_obj_t * elevation_canvas = ext->elevation_ext.elevation_canvas;
    elevation_add_record(elevation_canvas, x, LV_COLOR_BLACK, LV_COLOR_BLUE);
    lv_obj_invalidate(elevation_canvas);

    snprintf(str, 20, "%d %s", elevation_data[x] - 800, (char *)lv_lang_get_text(WATCH_TEXT_ID_METER));
    lv_label_set_text(ext->elevation_ext.current_rate, str);

    memset(str, 0, 20);
    snprintf(str, 20, "%d", elevation_data[elevation_mng.highest_x] - 800);
    lv_label_set_text(ext->elevation_ext.highest_rate, str);

    memset(str, 0, 20);
    snprintf(str, 20, "%d", elevation_data[elevation_mng.lowest_x] - 800);
    lv_label_set_text(ext->elevation_ext.lowest_rate, str);

    float delta =  (float)elevation_data[x]/ ELEVATION_GOAL_STEP;
    int16_t val = delta * (ELEVATION_CIRCLE_END - ELEVATION_CIRCLE_START) + ELEVATION_CIRCLE_START + 900;
    int16_t val_sub = val % 3600;
    if((val_sub < ELEVATION_CIRCLE_START + 900) && (val_sub > 600)) val = 600;
    lv_img_set_angle(ext->elevation_ext.elevation_goal, val);
}

static void elevation_update_task(lv_anim_t *a)
{
    elevation_update_display(a->var, elevation_mng.current_x);
    if(elevation_mng.current_x != ELEVATION_W - 1)
        elevation_mng.current_x++;
}

static void elevation_update_start(lv_obj_t * obj)
{
    uint16_t i;

    printf("currentx %d\n", elevation_mng.current_x);
    for(i = 0; i < elevation_mng.current_x; i++) {
        elevation_update_display(obj, i);
    }

    lv_anim_t a;
    lv_anim_init(&a);
    lv_anim_set_var(&a, obj);
    lv_anim_set_time(&a, 1);
    lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
    lv_anim_set_repeat_delay(&a, ELEVATION_UPDATE_PERIOD);       // update every 1s
    lv_anim_set_start_cb(&a, elevation_update_task);
    lv_anim_start(&a);
}

static lv_obj_t * elevation_create(lv_obj_t * tileview, uint16_t id)
{
    lv_obj_t * tab = elevation_pressure_tileview_add_tile(tileview, id);
    LV_ASSERT_MEM(tab);
    if(tab == NULL) return NULL;

    lv_obj_t * img_color_circle = lv_img_create(tab, NULL);
    LV_ASSERT_MEM(img_color_circle);
    if(img_color_circle == NULL) return NULL;
    lv_img_set_src(img_color_circle, ICON_COLOR_CIRCLE);
    lv_img_set_zoom(img_color_circle,LV_IMG_ZOOM_NONE * lv_obj_get_width(tab) / 240);
    lv_obj_add_style(img_color_circle, LV_IMG_PART_MAIN, &lv_watch_image);
    lv_obj_align(img_color_circle, tab, LV_ALIGN_CENTER, 0, 0);
    lv_obj_t * elevation_goal = lv_img_create(tab, NULL);
    lv_img_set_src(elevation_goal, ICON_STEP_DOT);
    lv_img_set_zoom(elevation_goal,LV_IMG_ZOOM_NONE * lv_obj_get_width(tab) / 240);
    lv_coord_t img_w = lv_obj_get_width(elevation_goal);
    lv_coord_t tab_w = lv_obj_get_width(tab);
    lv_coord_t radius = 0;
    if(tab_w > 240)
    {
        radius = tab_w / 2 - 33 - img_w / 2;
    }
    else
    {
        radius = tab_w / 2 - 18 * tab_w / 240 - img_w / 2;
    }

    lv_coord_t pivot_x = radius * 240 / tab_w;
    lv_img_set_pivot(elevation_goal,
                     -pivot_x,
                     lv_obj_get_height(elevation_goal) / 2);
    lv_obj_align(elevation_goal, tab, LV_ALIGN_IN_RIGHT_MID,
                 radius * 240 / tab_w + img_w - tab_w / 2, 0);

    lv_elevation_obj_ext_t * ext = elevation_pressure_get_ext();
    ext->elevation_ext.elevation_canvas = NULL;
    ext->elevation_ext.current_rate = NULL;
    ext->elevation_ext.highest_rate = NULL;
    ext->elevation_ext.lowest_rate = NULL;
    ext->elevation_ext.highest_dot = NULL;
    ext->elevation_ext.lowest_dot = NULL;
    ext->elevation_ext.elevation_goal = elevation_goal;

    lv_obj_t * label_content1 = lv_cont_create(img_color_circle, NULL);
    lv_obj_add_style(label_content1, LV_OBJ_PART_MAIN, &lv_watch_style_transp);
    lv_obj_set_size(label_content1, 100,60);
    lv_cont_set_layout(label_content1, LV_LAYOUT_COLUMN_MID);
    lv_obj_t * current_rate = lv_label_create(label_content1, NULL);
    lv_obj_add_style(current_rate,LV_LABEL_PART_MAIN, &lv_watch_font20_gray);
    lv_obj_set_size(current_rate, 100,20);
    lv_label_set_text_id(current_rate, WATCH_TEXT_ID_ELEVATION);
    //add current rate

    char str[20];
    current_rate = lv_label_create(label_content1, NULL);
    lv_obj_add_style(current_rate,LV_LABEL_PART_MAIN, &lv_watch_font20_yellow);
    ext->elevation_ext.current_rate = current_rate;
    lv_obj_set_size(current_rate, 100,20);
    snprintf(str, 20, "%d %s", 0, (char *)lv_lang_get_text(WATCH_TEXT_ID_METER));
    lv_label_set_text(current_rate, str);
    lv_obj_align(label_content1, img_color_circle, LV_ALIGN_CENTER, 0, -90);

    lv_obj_t * elevation_content = lv_cont_create(img_color_circle, NULL);
    lv_obj_add_style(elevation_content, LV_OBJ_PART_MAIN, &lv_watch_style_transp);
    lv_obj_set_size(elevation_content, ELEVATION_W, ELEVATION_HOR);
    lv_obj_align(elevation_content, label_content1, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);

    uint8_t color_size = lv_img_cf_get_px_size(LV_IMG_CF_TRUE_COLOR);
    uint32_t buff_size = (color_size * ELEVATION_W * ELEVATION_HOR) / 8;
    uint8_t * canvas_buff = lv_mem_alloc(buff_size);
    memset(canvas_buff, 0, buff_size);

    lv_obj_t * elevation_canvas = lv_canvas_create(elevation_content, NULL);
    ext->elevation_ext.elevation_canvas = elevation_canvas;
    lv_obj_set_size(elevation_canvas, ELEVATION_W, ELEVATION_HOR + 10);
    lv_canvas_set_buffer(elevation_canvas, canvas_buff, ELEVATION_W, ELEVATION_HOR, LV_IMG_CF_TRUE_COLOR);
    lv_obj_align(elevation_canvas, elevation_content, LV_ALIGN_IN_BOTTOM_LEFT, 0, -15);

    //add axis-x
    elevation_add_axis_x(elevation_content, elevation_canvas);
    lv_obj_t * highest_dot_img = lv_img_create(elevation_canvas, NULL);
    ext->elevation_ext.highest_dot = highest_dot_img;
    lv_img_set_src(highest_dot_img, ICON_HEART_RATE_HIGHEST_DOT);

    lv_obj_t * lowest_dot_img = lv_img_create(elevation_canvas, NULL);
    ext->elevation_ext.lowest_dot = lowest_dot_img;
    lv_img_set_src(lowest_dot_img, ICON_HEART_RATE_LOWEST_DOT);

    lv_obj_t * label_content2 = lv_cont_create(img_color_circle, NULL);
    lv_obj_add_style(label_content2, LV_OBJ_PART_MAIN, &lv_watch_style_transp);
    lv_obj_set_size(label_content2,100,30);
    lv_cont_set_layout(label_content2, LV_LAYOUT_ROW_MID);
    lv_obj_t * highest_img = lv_img_create(label_content2, NULL);
    lv_img_set_src(highest_img, ICON_ELEVATION_HIGHEST);
    //add highest rate
    lv_obj_t * highest_rate = lv_label_create(label_content2, NULL);
    ext->elevation_ext.highest_rate = highest_rate;
    lv_obj_set_style_local_text_font(highest_rate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_THEME_WATCH_NIGHT_FONT_30);
    lv_obj_set_style_local_text_color(highest_rate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);

    lv_label_set_text(highest_rate, "0");
    lv_obj_align(label_content2, elevation_content, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);

    lv_obj_t * label_content3 = lv_cont_create(img_color_circle, NULL);
    lv_obj_add_style(label_content3, LV_OBJ_PART_MAIN, &lv_watch_style_transp);
    lv_obj_set_size(label_content3, 100,30);
    lv_cont_set_layout(label_content3, LV_LAYOUT_ROW_MID);
    lv_obj_t * lowest_img = lv_img_create(label_content3, NULL);
    lv_img_set_src(lowest_img, ICON_ELEVATION_LOWEST);
    //add lowest rate
    lv_obj_t * lowest_rate = lv_label_create(label_content3, NULL);
    ext->elevation_ext.lowest_rate = lowest_rate;
    lv_obj_set_style_local_text_font(lowest_rate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_THEME_WATCH_NIGHT_FONT_30);
    lv_obj_set_style_local_text_color(lowest_rate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
    lv_label_set_text(lowest_rate, "0");
    lv_obj_align(label_content3, label_content2, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);

    lv_obj_t * label_content4 = lv_cont_create(tab, NULL);
    lv_obj_add_style(label_content4, LV_OBJ_PART_MAIN, &lv_watch_style_transp);
    lv_obj_set_size(label_content4, 30,30);
    lv_cont_set_layout(label_content4, LV_LAYOUT_OFF);
    lv_obj_t * label_up = lv_label_create(label_content4, NULL);
    lv_label_set_text(label_up, LV_SYMBOL_UP);
    lv_obj_align(label_up, label_content4, LV_ALIGN_CENTER, 0, 0);
    lv_obj_align(label_content4, tab, LV_ALIGN_IN_BOTTOM_MID, 0, -5);

#if ELEVATION_TEST
    elevation_test_init();
#endif

    elevation_update_start(tab);
    lv_tileview_add_element(tileview, elevation_goal);
    lv_watch_obj_add_element(elevation_goal);
    lv_tileview_add_element(tileview, img_color_circle);
    lv_watch_obj_add_element(img_color_circle);
    lv_tileview_add_element(tileview, elevation_content);
    lv_watch_obj_add_element(elevation_content);
    lv_tileview_add_element(tileview, label_content1);
    lv_watch_obj_add_element(label_content1);
    lv_tileview_add_element(tileview, label_content2);
    lv_watch_obj_add_element(label_content2);
    lv_tileview_add_element(tileview, label_content3);
    lv_watch_obj_add_element(label_content3);
    lv_tileview_add_element(tileview, label_content4);
    lv_watch_obj_add_element(label_content4);
    return tab;
}
static void elevation_pressure_create(lv_obj_t * activity_obj)
{
    if(NULL == activity_obj) {
        lv_watch_activity_ext_t activity_ext;
        memset(&activity_ext, 0, sizeof(lv_watch_activity_ext_t));
        activity_ext.actId = ACT_ID_ELEVATION;
        activity_ext.create = (lv_watch_activity_create_f_t)elevation_pressure_create;
        activity_ext.prepare_destory = elevation_pressure_prepare_destory;
        activity_obj = lv_watch_creat_activity_obj(&activity_ext);
    }
    /* watch obj */
    lv_obj_t * obj = lv_watch_obj_create(activity_obj);
    LV_ASSERT_MEM(obj);
    if(obj == NULL) {
        return;
    }
    lv_watch_obj_set_anim_mode(obj, LV_WATCH_ANIM_HOR_RIGHT_HIDE);
    lv_elevation_obj_ext_t * ext = lv_obj_allocate_ext_attr(activity_obj, sizeof(lv_elevation_obj_ext_t));
    memset(&ext->elevation_ext,0,sizeof(elevation_ext_t));
    memset(&ext->pressure_ext,0,sizeof(pressure_ext_t));
    lv_obj_t * img = lv_img_create(obj, NULL);
    lv_img_set_src(img, watch_get_bg());
    lv_obj_set_size(img, LV_HOR_RES, LV_VER_RES);
    lv_obj_t  * tileview = lv_tileview_create(obj, NULL);
    lv_elevation_drop_pull_obj_ext_t * ext_drop = lv_obj_allocate_ext_attr(tileview, sizeof(lv_elevation_drop_pull_obj_ext_t));
    (void)ext_drop;
    LV_ASSERT_MEM(tileview);
    lv_tileview_set_valid_positions(tileview, elevation_valid_pos, 2);
    lv_tileview_set_edge_flash(tileview, true);
    lv_tileview_set_anim_time(tileview, 60);
    lv_page_set_scrollbar_mode(tileview, LV_SCROLLBAR_MODE_OFF);
    lv_obj_add_style(tileview, LV_TILEVIEW_PART_EDGE_FLASH, &lv_watch_cont_opa1);
    lv_obj_t * tab;
    tab = elevation_create(tileview, 0);
    LV_ASSERT_MEM(tab);
    if(tab == NULL) return;
    tab = pressure_create(tileview, 1);
    LV_ASSERT_MEM(tab);
    if(tab == NULL) return;
    lv_tileview_set_valid_positions(tileview, elevation_valid_pos, sizeof(elevation_valid_pos) / sizeof(elevation_valid_pos[0]));
    lv_tileview_set_tile_act(tileview, 0, 0, false);
    lv_watch_obj_add_element(tileview);
    lv_watch_obj_add_element(lv_page_get_scrl(tileview));
}

static void elevation_pressure_prepare_destory(lv_obj_t * activity_obj)
{
    lv_elevation_obj_ext_t * ext = elevation_pressure_get_ext();
    lv_canvas_ext_t * canvas_ext = NULL;
    if(ext)
    {
        canvas_ext = lv_obj_get_ext_attr(ext->elevation_ext.elevation_canvas);
    }
    if((NULL != canvas_ext))
    {
        if(NULL != canvas_ext->dsc.data)
            lv_mem_free(canvas_ext->dsc.data);
    }

    if(ext)
    {
        canvas_ext = lv_obj_get_ext_attr(ext->pressure_ext.pressure_canvas);
    }
    if((NULL != canvas_ext))
    {
        if(NULL != canvas_ext->dsc.data)
            lv_mem_free(canvas_ext->dsc.data);
    }
    lv_watch_png_cache_all_free();
}

/**********************
 *   GLOBAL FUNCTIONS
***********************/
lv_elevation_obj_ext_t * elevation_pressure_get_ext(void)
{
    lv_obj_t * activity_obj = lv_watch_get_activity_obj(ACT_ID_ELEVATION);
    if(activity_obj == NULL) return NULL;
    if(activity_obj) {
        lv_elevation_obj_ext_t * ext = lv_obj_get_ext_attr(activity_obj);
        return ext;
    }
    return NULL;
}

lv_obj_t * elevation_pressure_tileview_add_tile(lv_obj_t * tileview, uint16_t id)
{
    lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);
    lv_obj_t * cont = lv_cont_create(tileview, NULL);
    lv_obj_set_style_local_bg_color(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
    lv_obj_set_size(cont, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_y(cont, LV_VER_RES * ext->valid_pos[id].y);
    lv_tileview_add_element(tileview, cont);
    lv_obj_set_click(cont, false);
    lv_cont_set_layout(cont, LV_LAYOUT_OFF);
    return cont;
}

void elevation_add_axis_x(lv_obj_t * par, lv_obj_t * align_obj)
{
    lv_obj_t * axis_x = lv_obj_create(par, NULL);
    lv_obj_set_style_local_border_width(axis_x, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, 1);
    lv_obj_set_style_local_border_color(axis_x, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
    lv_obj_set_style_local_border_opa(axis_x, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
    lv_obj_set_size(axis_x, ELEVATION_W, 1);
    lv_obj_align(axis_x, align_obj, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);

    elevation_add_dot(par, axis_x, 0, NULL);
    elevation_add_dot(par, axis_x, 20, "6:00");
    elevation_add_dot(par, axis_x, 40, NULL);
    elevation_add_dot(par, axis_x, 60, "12:00");
    elevation_add_dot(par, axis_x, 80, NULL);
    elevation_add_dot(par, axis_x, 100, "18:00");
    elevation_add_dot(par, axis_x, 120, NULL);
}

void elevation_pressure_create_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e)
        elevation_pressure_create(NULL);
}

#endif /*USE_LV_WATCH_ELEVATION*/
